﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using AutoMapper;
using AutoMapper.Configuration;
using log4net;
using log4net.Config;
using log4net.Repository;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Shop.Entity;
using Shop.Interface;
using Shop.Tools;
using Shop.Web.Filter;
using Shop.Web.Models;
using IConfiguration = Microsoft.Extensions.Configuration.IConfiguration;

namespace Shop.Web
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            //配置 log4net
            repository = LogManager.CreateRepository("NETCoreRepository");
            // 指定配置文件
            XmlConfigurator.Configure(repository, new FileInfo("log4net.xml"));
            Configuration = configuration;
        }

        public static ILoggerRepository repository { get; set; }
        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            #region 配置Session  Session存入Redis

            var redisCon = Configuration["RedisConfig:Connection"];
            var redisInstanceName = Configuration["RedisConfig:InstanceName"];
            var sessionOutTime = Configuration.GetValue<int>("SessionTimeOut", 30);
            //配置Redis存储
            services.AddDistributedRedisCache(options => { options.Configuration = redisCon; options.InstanceName = redisInstanceName; });
            //配置session 和超时
            services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(sessionOutTime); });

            //读取Redis配置 【全局使用】
            StaticConst.RedisConfig = Configuration["RedisConfig:ConnectionData"];
            #endregion

            #region 暂时不用 【框架自带】

  //          //添加认证Cookie信息
  //          services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  //.AddCookie(options =>
  //                  {
  //                      options.LoginPath = new PathString("/Home/Index");
  //                      options.AccessDeniedPath = new PathString("/Home/Index");
  //                  });

            #endregion


            #region 注册SignalR

            services.AddSignalR();

            #endregion

            #region 注册AutoMapper

            //获取所有IProfile实现类
            var allType = Assembly.GetEntryAssembly()//获取默认程序集
                    .GetReferencedAssemblies()//获取所有引用程序集
                    .Select(Assembly.Load).SelectMany(y => y.DefinedTypes).Where(type => typeof(AutoMapperBase).GetTypeInfo().IsAssignableFrom(type.AsType()));
            var cfg = new MapperConfigurationExpression();
            allType.ToList().ForEach(x =>
            {
                var types = x.AsType();
                if (typeof(AutoMapperBase).IsAssignableFrom(types) && !types.IsInterface)
                    cfg.AddProfile(types);
            });
            Mapper.Initialize(cfg);
            //这个语句只能放在注册后，不然会报错【报配置不正确】
            services.AddAutoMapper();
            #endregion

            //注册系统全局异常日志处理
            services.AddMvc(option => {
                //全局异常捕获
                option.Filters.Add<ExceptionFilter>();
                //登录及权限验证
                option.Filters.Add<SignFilter>();
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            //注册日志 【全局使用】
            StaticConst.log = log4net.LogManager.GetLogger(repository.Name, "系统日志");
            //配置SqlServer 连接字符串
            StaticConst.SqlConfig = Configuration["SqlConString"];
            //配置Oracle 连接字符串
            StaticConst.OracleConfig = Configuration["OracleConString"];
            //配置 AutoFac
            ContainerBuilder builder = new ContainerBuilder();
            builder.Populate(services);

            #region 注册组件
            //公共接口
            var baseType = typeof(IBase);
            var arrAssembly = JsonConvert.DeserializeObject<List<string>>(Configuration["Components"]);
            if (arrAssembly.Any())
            {
                arrAssembly.ForEach(x =>
                {   //根据Dll名称，读取Dll
                    var assembly = Assembly.Load(x);
                    //注册组件
                    builder.RegisterAssemblyTypes(assembly).Where(t => baseType.IsAssignableFrom(t) && t != baseType).AsImplementedInterfaces().InstancePerLifetimeScope();
                });
            }
            #endregion


            var applicationContainer = builder.Build();
            return new AutofacServiceProvider(applicationContainer);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            #region 使用Session

            app.UseSession();

            #endregion

            #region 注册组件

            app.UseSignalR(x => { x.MapHub<MessageHub>("/sysmsg"); });

            #endregion

            #region 暂时不用 【框架自带】

            //app.UseAuthentication();

            #endregion

            app.UseMvc(routes =>
            {
                //配置区域
                routes.MapRoute(
                    name: "area",
                    template: "{area:exists}/{controller=Default}/{action=Index}/{id?}");
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

            app.UseCookiePolicy();
        }
    }
}
